//
// Created by LONG on 2020/10/18.
//

#include <string.h>
#include "../../include/utils/list.h"
#include "../../include/hwal/commDef.h"

void LIST_Init(S_List *self)
{
    WRITE_ONCE(self->next, self);
    self->prev = self;
}

void LIST_Final(S_List *self)
{
    while (!LIST_Empty(self))
    {
        LIST_Remove(self->next);
    }
}

/*
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __LIST_Add(S_List *prev, S_List *next, S_List *node)
{
    next->prev = node;
    node->next = next;
    node->prev = prev;
    WRITE_ONCE(prev->next, node);
}

/**
 * LIST_Add - add a new entry
 * @new: new entry to be added
 * @head: self head to add it after
 *
 * Insert a new entry after the specified head.
 * This is good for implementing stacks.
 */
void LIST_Prepend(S_List *self, S_List *node)
{
    __LIST_Add(self, self->next, node);
}

/**
 * LIST_Add_tail - add a new entry
 * @new: new entry to be added
 * @head: self head to add it before
 *
 * Insert a new entry before the specified head.
 * This is useful for implementing queues.
 */
void LIST_Append(S_List *self, S_List *node)
{
    __LIST_Add(self->prev, self, node);
}

/**
 * list_del - deletes entry from list.
 * @entry: the element to delete from the list.
 * Note: LIST_Empty() on entry does not return true after this, the entry is
 * in an undefined state.
 */
static inline void __LIST_Remove(S_List *node)
{
    S_List * prev;
    S_List * next;

    prev = node->prev;
    next = node->next;

    next->prev = prev;
    WRITE_ONCE(prev->next, next);
}

void LIST_Remove(S_List *node)
{
    if (node->next && node->prev)
    {
        __LIST_Remove(node);
        node->next = NULL;
        node->prev = NULL;
    }
}

void LIST_Join(S_List *dst, S_List *src)
{
    if (dst == src)
    {
        return;
    }
    if (LIST_Empty(src))
    {
        return;
    }
    if (LIST_Empty(dst))
    {
        dst->next = src->next;
        dst->prev = src->prev;
        src->next->prev = dst;
        src->prev->next = dst;
        LIST_Init(src);
        return;
    }
    dst->prev->next = src->next;
    src->next->prev = dst->prev;
    src->prev->next = dst;
    dst->prev = src->prev;
    LIST_Init(src);
}

/**
 * LIST_Empty - tests whether a list is empty
 * @head: the self to test.
 */
int32_t LIST_Empty(const S_List *self)
{
    return READ_ONCE(self->next) == self;
}
